package com.m4f.city.web.controller.user;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.cache.CacheException;
import javax.validation.Valid;

import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.m4f.city.business.domain.Application;
import com.m4f.city.business.domain.InternalUser;
import com.m4f.city.business.domain.Organization;
import com.m4f.city.business.domain.oauth2.OAuth2AccessTokenDS;
import com.m4f.city.business.security.InternalUserDetailService;
import com.m4f.city.web.controller.BaseController;
import com.m4f.city.web.form.UserForm;
import com.m4f.gaeweb.exception.M4FException;
import com.m4f.gaeweb.web.utils.StackTraceUtil;

@Controller
@Secured(InternalUserDetailService.ROLE_USER)
@RequestMapping("/user")
public class UserController extends BaseController {
	private static final Logger LOGGER = Logger.getLogger(UserController.class.getName());
	
	public UserController() throws CacheException {
		super();
	}
	
	@RequestMapping(value="/information", method=RequestMethod.GET)
	public String getInformation(Principal principal, Model model, Locale locale) {
		try {
			InternalUser user = getInternalUser(principal);
			user.setPassword(""); // Clean the passwd
			model.addAttribute("form", new UserForm(user));
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			return "common.error";
		}
		return "user.information";
	}
	
	@RequestMapping(value="/information", method=RequestMethod.POST)
	public String saveInformation(Principal principal, @ModelAttribute("form") @Valid UserForm form, BindingResult result,
			Model model, Locale locale) throws M4FException {
		// Mapping the fields that one user can edit. For security.
		InternalUser updatedUser = getInternalUser(principal);
		if(!result.hasErrors()) {
			InternalUser user = form.getUser();
			// EMAIL (USERNAME)
			updatedUser.setEmail(user.getEmail());
			// PASSWORD
			Object salt = null;
			Md5PasswordEncoder encoder = new Md5PasswordEncoder();
			updatedUser.setPassword(encoder.encodePassword(user.getPassword(), salt));
			// NAME
			updatedUser.setName(user.getName());
			// SURNAME
			updatedUser.setSurname(user.getSurname());
			// NickName
			updatedUser.setNickname(user.getNickname());
			// TODO Avatar
			
			try {
				this.serviceLocator.getUserService().save(updatedUser);
				addSuccessMessage("message.success.user.information.updated");
			} catch(Exception e) {
				LOGGER.log(Level.SEVERE, StackTraceUtil.getStackTrace(e));
				addErrorMessage("message.error.user.information.updated");
			}
		}
		
		return "user.information";
	}
	
	@RequestMapping(value="/applications", method=RequestMethod.GET)
	public String getApplications(Principal principal, Model model, Locale locale) {
		try {
			InternalUser user = getInternalUser(principal);
			Collection<OAuth2AccessTokenDS> accessTokens = this.serviceLocator.getOAuth2TokensService().getAllAccessToken(user.getId(), null);
			List<Application> apps = new ArrayList<Application>();
			for(OAuth2AccessTokenDS accessToken : accessTokens) {
				Application app = this.serviceLocator.getApplicationService().getAppliaction(accessToken.getClientId());
				apps.add(app);
			}
			
			model.addAttribute("user", user);
			model.addAttribute("apps", apps);
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			return "common.error";
		}
		return "user.applications";
	}
	
	@RequestMapping(value="/applications/{appId}", method=RequestMethod.GET)
	public String getApplicationDetail(@PathVariable Long appId, Principal principal, Model model, Locale locale) {
		// TODO
		return "user.applications";
	}
	
	@RequestMapping(value="/applications/revoke/{appId}", method=RequestMethod.GET)
	public String getRevokeApplication(@PathVariable Long appId, Principal principal, Model model, Locale locale) {
		try {
			InternalUser user = getInternalUser(principal);
			Application app = this.serviceLocator.getApplicationService().getObjectById(appId);
			this.serviceLocator.getOAuth2TokensService().removeAccessToken(user.getId(), app.getClientId());
			addSuccessMessage("message.success.user.application.revoked");
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			addErrorMessage("message.error.user.application.revoked");
		}
		return "redirect:/" + locale.getLanguage() + "/user/applications";
	}
	
	@ModelAttribute("organization")
	public Organization getOrganization(Principal principal) throws M4FException {
		InternalUser user = getInternalUser(principal);
		try {
			return this.serviceLocator.getOrganizationService().getOrganization(user.getOrganizationId());
		} catch(Exception e) {
			// TODO
			return null;
		}
	}
}